/*
	Pulsar engine. Core.
	String conversions (multibyte, unicode, utf8)

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

#include <pulsar/pulsar.h>

namespace pl
{

static const pl_uint16* _translationTable = NULL;
static char _crossTranslationTable[256];
static int _unicodeHighCacheValue;

pl_uint16 _codepage1251[128] =
{
	0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
	0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
	0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
	0x0098, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
	0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
	0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
	0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
	0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
	0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
	0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
	0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
	0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
	0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
	0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F
};

} // namespace pl

/**
	Set new codepage to convert multibyte chars into unicode and back
*/
void pl::setCurrentCodepage(const pl_uint16* translationTable)
{
	int i, findCounter[256] = {0};
	int maxIndex, maxValue;
	_translationTable = translationTable;

	if (translationTable == NULL)
	{
		// No translation for chars > 127
		return;
	}

	// Calculate most used highword for fastest access
	for (i=0; i<128; i++)
	{
		findCounter[(translationTable[i] & 0xFF00) >> 8]++;
	}

	maxIndex = 0; maxValue = findCounter[0];
	for (i=1; i<256; i++)
	{
		if (findCounter[i] > maxValue)
		{
			maxValue = findCounter[i];
			maxIndex = i;
		}
	}

	// Fill cross hash value
	memset(_crossTranslationTable, 0, sizeof(_crossTranslationTable));
	_unicodeHighCacheValue = maxIndex << 8;
	for (i=0; i<128; i++)
	{
		if ((translationTable[i] & 0xFF00) == _unicodeHighCacheValue)
		{
			_crossTranslationTable[translationTable[i] & 0xFF] = static_cast<char>(128 + i);
		}
	}
	return;
}

/*
	Convert character from multibyte to unicode
*/
void pl::convertChar(char c, wchar_t& res)
{
	if (c & 0x80)
	{
		res = _translationTable ? _translationTable[(pl_uint8)c - 128] : PL_T('.');
	}
	else
	{
		res = (c & 0x7F);
	}
	return;
}

/*
	Convert string from ANSI to Unicode
*/
void pl::convertStr(const char* src, wchar_t* dest, pl_uint32 destSize)
{
	pl_uint32 i;

	if (src == NULL || dest == NULL || destSize == 0)
	{
		PL_ASSERTW(FALSE, PL_T("Wrong arguments"));
	}
	for (i=0; src[i] != '\0'; i++)
	{
		convertChar(src[i], dest[i]);
		if (i >= destSize-1)
		{
			PL_ASSERTE(FALSE, PL_T("Output buffer overflow"));
			break;
		}
	}
	dest[i] = PL_T('\0');
	return;
}

/*
	Convert from UNICODE to ANSI
*/
void pl::convertChar(wchar_t c, char& res)
{
	if ((pl_uint32)(c) > 127)
	{
		// Checking _translationTable
		if (_translationTable == NULL)
		{
			res = PL_T('.');
			return;
		}

		if (_unicodeHighCacheValue == (c & 0xFF00))
		{
			// Use cross-value
			res = _crossTranslationTable[c & 0xFF];
			return;

		}
		// Looking in all table
		int i;
		for (i=0; i<128; i++)
		{
			if (_translationTable[i] == c)
			{
				res = static_cast<char>(128 + i);
				return;
			}
		}
		// Not found
		res = PL_T('.');
		return;
	}
	res = static_cast<char>(c & 0x007F);
	return;
}

/*
	Convert from UNICODE to ANSI
*/
void pl::convertStr(const wchar_t* src, char* dest, pl_uint32 destSize)
{
	pl_uint32 i;

	if (src == NULL || dest == NULL || destSize == 0)
	{
		PL_ASSERTW(FALSE, PL_T("Wrong arguments"));
	}
	for (i=0; src[i] != PL_T('\0'); i++)
	{
		convertChar(src[i], dest[i]);
		if (i >= destSize-1)
		{
			break;
		}
	}
	dest[i] = PL_T('\0');
	return;
}

/*
	Convert from ANSI to UTF8
*/
void pl::convertStr(const char* src, pl_char8* dest, pl_uint32 destSize)
{
	PL_BREAK(); // TODO - not implemented
}

/*
	Convert from UTF8 to ANSI
*/
void pl::convertStr(const pl_char8* src, char* dest, pl_uint32 destSize)
{
	PL_BREAK(); // TODO - not implemented
}

/*
	Convert from UNICODE to UTF8
*/
void pl::convertStr(const wchar_t* src, pl_char8* dest, pl_uint32 destSize)
{
	PL_BREAK(); // TODO - not implemented
}

/*
	Convert from UTF8 to UNICODE
*/
void pl::convertStr(const pl_char8* src, wchar_t* dest, pl_uint32 destSize)
{
	PL_BREAK(); // TODO - not implemented
}

int pl::convertChar(char c, pl_char8* buf)
{
	PL_BREAK(); // TODO - not implemented
	return 0;
}

int pl::convertChar(wchar_t c, pl_char8* buf)
{
	PL_BREAK(); // TODO - not implemented
	return 0;
}

void pl::convertChar(const pl_char8* src, wchar_t& res)
{
	PL_BREAK(); // TODO - not implemented
}

void pl::convertChar(const pl_char8* src, char& res)
{
	PL_BREAK(); // TODO - not implemented
}

//
// End of file 'pulsar_string_convert.cpp'
//
